;
; File     : X86_64_Windows.s
; Created  : 3 May 2011
;
; Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU Lesser General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU Lesser General Public License for more details.
;
; You should have received a copy of the GNU Lesser General Public License
; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

EXTRN	__imp_GetLastError:PROC

_TEXT SEGMENT

.CODE


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 1 argument                                                          ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_1 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home

    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    jmp       r8

dni_x64_windows_call_1 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 2 arguments                                                         ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_2 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;   <..>      arg1
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg1


    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    mov       rdx, qword ptr [ rsp + 40 ]
    movd      xmm1, rdx

    jmp       r8

dni_x64_windows_call_2 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 3 arguments                                                         ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_3 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg1
    ;   rsp + 48: arg2


    ; preserve function pointer
    mov       r10, r8

    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    mov       rdx, qword ptr [ rsp + 40 ]
    mov       r8,  qword ptr [ rsp + 48 ]
    movd      xmm1, rdx
    movd      xmm2, r8

    jmp       r10

dni_x64_windows_call_3 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 4 arguments                                                         ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_4 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;   <..>      arg3
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       arg0  \_ either
    ;   xmm3:     arg0  /    or
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg1
    ;   rsp + 48: arg2
    ;   rsp + 56: arg3


    ; preserve function pointer
    mov       r10, r8

    ; move displaced argument
    mov       rcx, r9
    movq      xmm0, xmm3

    mov       rdx, qword ptr [ rsp + 40 ]
    mov       r8,  qword ptr [ rsp + 48 ]
    mov       r9,  qword ptr [ rsp + 56 ]
    movd      xmm1, rdx
    movd      xmm2, r8
    movd      xmm3, r9

    jmp       r10

dni_x64_windows_call_4 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for >4 arguments                                                        ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_displace_4 PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      offset to displaced arguments
    ;   <..>      arg4...
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;   <..>      arg3
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       offset
    ;
    ; Stack:
    ;   rsp +  0     : return address
    ;   rsp +  8     : rcx home
    ;   rsp + 16     : rdx home
    ;   rsp + 24     : r8 home
    ;   rsp + 32     : r9 home
    ;   rsp + 40     : arg4...
    ;   rsp + r9 +  0: arg0
    ;   rsp + r9 +  8: arg1
    ;   rsp + r9 + 16: arg2
    ;   rsp + r9 + 24: arg3


    ; preserve function pointer
    mov       r10, r8

    ; locate displaced arguments
    add       r9, rsp

    ; retrieve displaced arguments
    mov       rcx, qword ptr [ r9 +  0 ]
    mov       rdx, qword ptr [ r9 +  8 ]
    mov       r8,  qword ptr [ r9 + 16 ]
    mov       r9,  qword ptr [ r9 + 24 ]
    movd      xmm0, rcx
    movd      xmm1, rdx
    movd      xmm2, r8
    movd      xmm3, r9

    jmp       r10

dni_x64_windows_call_displace_4 ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 'n' arguments                                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_n PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      argptr
    ;   int       argcount
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       argptr
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: count (in 64-bit units)


    ; prologue
    push      rbp
    mov       rbp, rsp
    push      rsi
    push      rdi

    ; preserve function pointer
    mov       rax, r8

    ; retrieve arg count
    mov       rcx, qword ptr [ rbp + 8 + 40 ]

    ; allocate stack for call
    lea       rdi, qword ptr [ 0 + 8 * rcx ]
    sub       rsp, rdi

    ; copy the spill arguments (all but the first four)
    lea       rsi, qword ptr [ r9  + 32 ]
    lea       rdi, qword ptr [ rsp + 32 ]
    sub       rcx, 4
    rep movsq

    ; retrieve the register arguments
    mov       rcx, qword ptr [ r9 +  0 ]
    mov       rdx, qword ptr [ r9 +  8 ]
    mov       r8,  qword ptr [ r9 + 16 ]
    mov       r9,  qword ptr [ r9 + 24 ]
    movd      xmm0, rcx
    movd      xmm1, rdx
    movd      xmm2, r8
    movd      xmm3, r9

    call      rax

    ; clean the stack
    lea       rsp, [ rbp - 16 ]

    ; epilogue
    pop       rdi
    pop       rsi
    mov       rsp, rbp
    pop       rbp

    ret

dni_x64_windows_call_n ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for no arguments with GetLastError                                      ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; TODO v2.0 could be slightly optimised if we didn't want to create a full frame

dni_x64_windows_call_0_gle PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      lastErrorSlotPtr
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       lastErrorSlotPtr
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home

    ; prologue
    push       rbp
    mov        rbp, rsp
    mov        qword ptr [ rbp + 40 ], r9

    ; call the function
    ; (32 bytes for the spill area)
    sub        rsp, 32
    call       r8

    ; keep the return result in this call's JNIEnv/jclass pointer's slot (nasty)
    mov        qword ptr [ rbp + 16 ], rax
    movq       qword ptr [ rbp + 24 ], xmm0

    ; call GetLastError
    call       qword ptr __imp_GetLastError

    ; keep the error code
    mov        r9, qword ptr [ rbp + 40 ]
    mov        dword ptr [ r9 ], eax

    ; restore the return result
    mov        rax, qword ptr [ rbp + 16 ]
    movq       xmm0, qword ptr [ rbp + 24 ]

    ; epilogue
    mov        rsp, rbp
    pop        rbp
    ret

dni_x64_windows_call_0_gle ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 1 argument with GetLastError                                        ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_1_gle PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      lastErrorSlotPtr
    ;   <..>      arg0
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       lastErrorSlotPtr
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg0

    ; prologue
    push       rbp
    mov        rbp, rsp
    mov        qword ptr [ rbp + 40 ], r9

    ; get argument for function
    mov        rcx, qword ptr [ rbp + 48 ]
    movd       xmm0, rcx

    ; call the function
    ; (32 bytes for the spill area)
    sub        rsp, 32
    call       r8

    ; keep the return result in this call's JNIEnv/jclass pointer's slot (nasty)
    mov        qword ptr [ rbp + 16 ], rax
    movq       qword ptr [ rbp + 24 ], xmm0

    ; call GetLastError
    call       qword ptr __imp_GetLastError

    ; keep the error code
    mov        r9, qword ptr [ rbp + 40 ]
    mov        dword ptr [ r9 ], eax

    ; restore the return result
    mov        rax, qword ptr [ rbp + 16 ]
    movq       xmm0, qword ptr [ rbp + 24 ]

    ; epilogue
    mov        rsp, rbp
    pop        rbp
    ret

dni_x64_windows_call_1_gle ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 2 arguments with GetLastError                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_2_gle PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      lastErrorSlotPtr
    ;   <..>      arg0
    ;   <..>      arg1
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       lastErrorSlotPtr
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg0
    ;   rsp + 48: arg1

    ; prologue
    push       rbp
    mov        rbp, rsp
    mov        qword ptr [ rbp + 40 ], r9

    ; get arguments for function
    mov        rcx, qword ptr [ rbp + 48 ]
    mov        rdx, qword ptr [ rbp + 56 ]
    movd       xmm0, rcx
    movd       xmm1, rdx

    ; call the function
    ; (32 bytes for the spill area)
    sub        rsp, 32
    call       r8

    ; keep the return result in this call's JNIEnv/jclass pointer's slot (nasty)
    mov        qword ptr [ rbp + 16 ], rax
    movq       qword ptr [ rbp + 24 ], xmm0

    ; call GetLastError
    call       qword ptr __imp_GetLastError

    ; keep the error code
    mov        r9, qword ptr [ rbp + 40 ]
    mov        dword ptr [ r9 ], eax

    ; restore the return result
    mov        rax, qword ptr [ rbp + 16 ]
    movq       xmm0, qword ptr [ rbp + 24 ]

    ; epilogue
    mov        rsp, rbp
    pop        rbp
    ret

dni_x64_windows_call_2_gle ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 3 arguments with GetLastError                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_3_gle PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      lastErrorSlotPtr
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       lastErrorSlotPtr
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg0
    ;   rsp + 48: arg1
    ;   rsp + 56: arg2

    ; prologue
    push       rbp
    mov        rbp, rsp
    mov        qword ptr [ rbp + 40 ], r9

    ; preserve the function pointer
    mov        rax, r8

    ; get arguments for function
    mov        rcx, qword ptr [ rbp + 48 ]
    mov        r8, qword ptr [ rbp + 56 ]
    mov        r9, qword ptr [ rbp + 64 ]
    movd       xmm0, rcx
    movd       xmm1, rdx
    movd       xmm2, rdx

    ; call the function
    ; (32 bytes for the spill area)
    sub        rsp, 32
    call       rax

    ; keep the return result in this call's JNIEnv/jclass pointer's slot (nasty)
    mov        qword ptr [ rbp + 16 ], rax
    movq       qword ptr [ rbp + 24 ], xmm0

    ; call GetLastError
    call       qword ptr __imp_GetLastError

    ; keep the error code
    mov        r9, qword ptr [ rbp + 40 ]
    mov        dword ptr [ r9 ], eax

    ; restore the return result
    mov        rax, qword ptr [ rbp + 16 ]
    movq       xmm0, qword ptr [ rbp + 24 ]

    ; epilogue
    mov        rsp, rbp
    pop        rbp
    ret

dni_x64_windows_call_3_gle ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for 4 arguments with GetLastError                                       ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_4_gle PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      lastErrorSlotPtr
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;   <..>      arg3
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       lastErrorSlotPtr
    ;
    ; Stack:
    ;   rsp +  0: return address
    ;   rsp +  8: rcx home
    ;   rsp + 16: rdx home
    ;   rsp + 24: r8 home
    ;   rsp + 32: r9 home
    ;   rsp + 40: arg0
    ;   rsp + 48: arg1
    ;   rsp + 56: arg2
    ;   rsp + 64: arg3

    ; prologue
    push       rbp
    mov        rbp, rsp
    mov        qword ptr [ rbp + 40 ], r9

    ; preserve the function pointer
    mov        rax, r8

    ; get arguments for function
    mov        rcx, qword ptr [ rbp + 48 ]
    mov        rdx, qword ptr [ rbp + 56 ]
    mov        r8, qword ptr [ rbp + 64 ]
    mov        r9, qword ptr [ rbp + 72 ]
    movd       xmm0, rcx
    movd       xmm1, rdx
    movd       xmm2, rdx
    movd       xmm3, rdx

    ; call the function
    ; (32 bytes for the spill area)
    sub        rsp, 32
    call       rax

    ; keep the return result in this call's JNIEnv/jclass pointer's slot (nasty)
    mov        qword ptr [ rbp + 16 ], rax
    movq       qword ptr [ rbp + 24 ], xmm0

    ; call GetLastError
    call       qword ptr __imp_GetLastError

    ; keep the error code
    mov        r9, qword ptr [ rbp + 40 ]
    mov        dword ptr [ r9 ], eax

    ; restore the return result
    mov        rax, qword ptr [ rbp + 16 ]
    movq       xmm0, qword ptr [ rbp + 24 ]

    ; epilogue
    mov        rsp, rbp
    pop        rbp
    ret

dni_x64_windows_call_4_gle ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Call for >4 arguments with GetLastError                                      ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dni_x64_windows_call_displace_4_gle PROC

    ; Java JNI signature is:
    ;   long      fnptr
    ;   long      offset to displaced arguments
    ;   <..>      arg4...
    ;   <..>      arg0
    ;   <..>      arg1
    ;   <..>      arg2
    ;   <..>      arg3
    ;   long      lastErrorSlotPtr
    ;
    ; Registers:
    ;   rcx:      JNIEnv*
    ;   rdx:      jclass
    ;   r8:       fnptr
    ;   r9:       offset
    ;
    ; Stack:
    ;   rsp +  0     : return address
    ;   rsp +  8     : rcx home
    ;   rsp + 16     : rdx home
    ;   rsp + 24     : r8 home
    ;   rsp + 32     : r9 home
    ;   rsp + 40     : arg4...
    ;   rsp + r9 +  0: arg0
    ;   rsp + r9 +  8: arg1
    ;   rsp + r9 + 16: arg2
    ;   rsp + r9 + 24: arg3
    ;   rsp + r9 + 32: lastErrorSlotPtr

    ; prologue
    push       rbp
    mov        rbp, rsp
    mov        qword ptr [ rbp + 40 ], r9

    ; preserve the function pointer
    mov        rax, r8

    ; locate displaced arguments
    lea        r9, qword ptr [ rbp + r9 + 8 ]

    ; retrieve displaced arguments
    mov        rcx, qword ptr [ r9 +  0 ]
    mov        rdx, qword ptr [ r9 +  8 ]
    mov        r8,  qword ptr [ r9 + 16 ]
    mov        r9,  qword ptr [ r9 + 24 ]
    movd       xmm0, rcx
    movd       xmm1, rdx
    movd       xmm2, r8
    movd       xmm3, r9

    ; call the function
    ; (32 bytes for the spill area)
    sub        rsp, 32
    call       rax

    ; keep the return result in this call's JNIEnv/jclass pointer's slot (nasty)
    mov        qword ptr [ rbp + 16 ], rax
    movq       qword ptr [ rbp + 24 ], xmm0

    ; call GetLastError
    call       qword ptr __imp_GetLastError

    ; keep the error code
    mov        r9, qword ptr [ rbp + 40 ]
    mov        dword ptr [ r9 ], eax

    ; restore the return result
    mov        rax, qword ptr [ rbp + 16 ]
    movq       xmm0, qword ptr [ rbp + 24 ]

    ; epilogue
    mov        rsp, rbp
    pop        rbp
    ret

dni_x64_windows_call_displace_4_gle ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


_TEXT ENDS

END
